Android 零散记录

  • PopupWindow与AlertDialog的区别

    最关键的区别是AlertDialog不能指定显示位置,只能默认显示在屏幕最中间(当然也可以通过设置WindowManager参数来改变位置)。而PopupWindow是可以指定显示位置的,随便哪个位置都可以,更加灵活。
    mPopWindow.showAtLocation(rootview, Gravity.BOTTOM, 0, 0);
  • 为什么叫Support v4,v7

    Android Support v4: 这个包是为了照顾1.6及更高版本而设计的,这个包是使用最广泛的,eclipse新建工程时,都默认带有了。
    Android Support v7: 这个包是为了考虑照顾2.1及以上版本而设计的,但不包含更低,故如果不考虑1.6,我们可以采用再加上这个包,另外注意,v7是要依赖v4这个包的,即,两个得同时被包含。
    Android Support v13 :这个包的设计是为了android 3.2及更高版本的,一般我们都不常用,平板开发中能用到。

  • 未解绑服务使得服务持有一个销毁的activity的context造成内存泄露

    MainActivity has leaked ServiceConnection com.skyace.service.MainActivity$1@41cd81f0 that was originally bound here
    服务没有解绑,造成内存泄露,onDestroy的回调方法中加入了对服务的解绑操作即 unbindService成功解决

  • handler中的handleMessage返回值

    return true 代表事件被处理了,其他handleMessage不会收到该msg
    return false 事件继续传递,外层的handleMessage() 会继续执行

  • FC问题从log中快速搜索has died

    11-18 10:10:59.380 V/CommandService( 495): Death received CommandThread:android.os.BinderProxy@41a1b1b8 in pid:1218
    随后搜索该pid 快速找到log

  • Fragment对于onActivityResult捕获不到的情况

    被父avtivity的onActivityResult捕获了

  • 软件盘的本质是什么?软键盘其实是一个Dialog!

    InputMethodService为我们的输入法创建了一个Dialog,并且将该Dialog的Window的某些参数(如Gravity)进行了设置,使之能够在底部或者全屏显示。当我们点击输入框时,系统对活动主窗口进行调整,从而为输入法腾出相应的空间,然后将该Dialog显示在底部,或者全屏显示。

  • 如何去掉字符串前后空格,或者说判断字符串是否为空,或者全部为空格

    TextUtils.isEmpty(mStr.trim()
    String类自带的trim()方法,能够去掉字符串前后空格

  • 如何使强制控制键盘弹起落下

1
2
3
4
5
6
7
8
9
10
11
12
public void showSoftKeyboard() {
mEditText.setFocusable(true);
mEditText.setFocusableInTouchMode(true);
mEditText.requestFocus();
InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.showSoftInput(mEditText, InputMethodManager.SHOW_FORCED);
}
public void hideSoftKeyboard() {
InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
}
  • 系统语言改变那点事

    当系统语言改变,当前Activity会进行重新创建,在生命方法中,我们可以在manifest中: android:configChanges=”locale” 语言(国家码)改变

    I/###xiamin( 8571): Setting onPause
    I/###xiamin( 8571): Setting onStop
    I/###xiamin( 8571): Setting onDestory
    I/###xiamin( 8571): Setting onCreate
    I/###xiamin( 8571): Setting onStart
    I/###xiamin( 8571): Setting onResume

  • Android模块

    keyguard(锁屏)模块
    SystemUI 通知栏和最近应用

  • Android分辨率适配终极方案

    android-support-percent-lib Android基于百分比的布局,谷歌官方推荐
    android-support-percent-lib鸿洋博客

  • SurfaceView

    普通的Android控件,例如TextView、Button和CheckBox等,它们都是将自己的UI绘制在宿主窗口的绘图表面之上,这意味着它们的UI是在应用程序的主线程中进行绘制的。由于应用程序的主线程除了要绘制UI之外,还需要及时地响应用户输入,否则的话,系统就会认为应用程序没有响应了,因此就会弹出一个ANR对话框出来。对于一些游戏画面,或者摄像头预览、视频播放来说,它们的UI都比较复杂,而且要求能够进行高效的绘制,因此,它们的UI就不适合在应用程序的主线程中进行绘制。这时候就必须要给那些需要复杂而高效UI的视图生成一个独立的绘图表面,以及使用一个独立的线程来绘制这些视图的UI。

  • android:splitMotionEvents

    定义布局是否传递触摸事件(touch)到子布局,true表示传递给子布局,false表示不传递。

  • 获取当前格式化时间

    1
    2
    3
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
    Date date = new Date(System.currentTimeMillis());
    String str = format.format(date);
  • Android为每个应用程序分配的内存大小

    过去是16M,不过根据机型而言不一样,早期的Android系统G1,就是只有16M

  • Android中内部存储和外部存储的理解和路径获取

    1.data/data/包名/shared_prefs
    2.data/data/包名/databases
    3.data/data/包名/files
    4.data/data/包名/cache

外部存储
外部存储才是我们平时操作最多的,外部存储一般就是我们上面看到的storage文件夹,当然也有可能是mnt文件夹,这个不同厂家有可能不一样。

一般来说,在storage文件夹中有一个sdcard文件夹,这个文件夹中的文件又分为两类,一类是公有目录,还有一类是私有目录,其中的公有目录有九大类,比如DCIM、DOWNLOAD等这种系统为我们创建的文件夹,私有目录就是Android这个文件夹,这个文件夹打开之后里边有一个data文件夹,打开这个data文件夹,里边有许多包名组成的文件夹。

所以外部存储的路径是:

storage/sdcard/Android/data/包名/files
storage/sdcard/Android/data/包名/cache

  • SharedPreferences也可以设置监听器

    mSharedPreferences.registerOnSharedPreferenceChangeListener(mOnSharedPreferenceChangeListener);

  • Android获取唯一机器码的代码

    String mDeviceId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);

  • 将内容复制到粘贴板

1
2
3
4
5
6
ClipboardManager copy = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData myClip;
String text = "" + mIdcode;
myClip = ClipData.newPlainText("text", text);
copy.setPrimaryClip(myClip);
Toast.makeText(WelcomeActivity.this, "复制成功", Toast.LENGTH_SHORT).show();
  • 监听屏幕唤醒和关闭的广播

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void registSreenStatusReceiver() {
mScreenStatusReceiver = new ScreenStatusReceiver();
IntentFilter screenStatusIF = new IntentFilter();
screenStatusIF.addAction(Intent.ACTION_SCREEN_ON);
screenStatusIF.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mScreenStatusReceiver, screenStatusIF);
}
unregisterReceiver(mScreenStatusReceiver);
class ScreenStatusReceiver extends BroadcastReceiver {
String SCREEN_ON = "android.intent.action.SCREEN_ON";
String SCREEN_OFF = "android.intent.action.SCREEN_OFF";
@Override
public void onReceive(Context context, Intent intent) {
if (SCREEN_ON.equals(intent.getAction())) {
}
else if (SCREEN_OFF.equals(intent.getAction())) {
}
}
}
  • Android应用的persistent属性

    android:persistent=”true”
    在Android系统中,有一种永久性应用。它们对应的AndroidManifest.xml文件里,会将persistent属性设为true
    在系统启动之时,AMS的systemReady()会加载所有persistent为true的应用。

  • 服务的前台运行(现在没什么用了)

    服务前台运行

  • 使用AIDL作为项目之间的接口可能存在一定的风险。

如何规避这个风险,网上有文章说,在IBinder里面的onTransact函数中调用Binder.getCallingUid()和Binder.getCallingPid()来判断外来方的身份。
但这个方法,只能是被调用方检测调用方的身份。
最近我的服务作为系统级服务存在的,但是其中的一个标志位出了问题,就是通过该方法找到是哪个进程改了的.

  • 如何导入外部数据库

    把原数据库包括在项目源码的 res/raw

android系统下数据库应该存放在 /data/data/com..(package name)/ 目录下,所以我们需要做的是把已有的数据库传入那个目录下.操作方法是用FileInputStream读取原数据库,再用FileOutputStream把读取到的东西写入到那个目录.

  • LaunchMode应用场景

    standard,创建一个新的Activity。

singleTop,栈顶不是该类型的Activity,创建一个新的Activity。否则,onNewIntent。

singleTask,回退栈中没有该类型的Activity,创建Activity,否则,onNewIntent+ClearTop。

注意:

设置了”singleTask”启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的Task存在; 如果存在这样的Task,它就会在这个Task中启动,否则就会在新的任务栈中启动。因此, 如果我们想要设置了”singleTask”启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。
如果设置了”singleTask”启动模式的Activity不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity实例, 如果存在,就会把位于这个Activity实例上面的Activity全部结束掉,即最终这个Activity 实例会位于任务的Stack顶端中。
在一个任务栈中只有一个”singleTask”启动模式的Activity存在。他的上面可以有其他的Activity。这点与singleInstance是有区别的。
singleInstance,回退栈中,只有这一个Activity,没有其他Activity。
singleTop适合接收通知启动的内容显示页面。

例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。

singleTask适合作为程序入口点。

例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。

singleInstance应用场景:

闹铃的响铃界面。 你以前设置了一个闹铃:上午6点。在上午5点58分,你启动了闹铃设置界面,并按 Home 键回桌面;在上午5点59分时,你在微信和朋友聊天;在6点时,闹铃响了,并且弹出了一个对话框形式的 Activity(名为 AlarmAlertActivity) 提示你到6点了(这个 Activity 就是以 SingleInstance 加载模式打开的),你按返回键,回到的是微信的聊天界面,这是因为 AlarmAlertActivity 所在的 Task 的栈只有他一个元素, 因此退出之后这个 Task 的栈空了。如果是以 SingleTask 打开 AlarmAlertActivity,那么当闹铃响了的时候,按返回键应该进入闹铃设置界面。

  • invalidate()和postInvalidate()的区别

可以把UI线程理解为主线程。其余的线程可以理解为工作者线程。
invalidate()得在UI线程中被调动,在工作者线程中可以通过Handler来通知UI线程进行界面更新。

而postInvalidate()在工作者线程中被调用

  • Android动画框架实现原理

Animation框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是整个View,实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧,如果动画没有完成,继续调用invalidate()函数,启动下次绘制来驱动动画,动画过程中的帧之间间隙时间是绘制函数所消耗的时间,可能会导致动画消耗比较多的CPU资源,最重要的是,动画改变的只是显示,并不能相应事件。

  • View刷新机制

由ViewRoot对象的performTraversals()方法调用draw()方法发起绘制该View树,值得注意的是每次发起绘图时,并不会重新绘制每个View树的视图,而只会重新绘制那些“需要重绘”的视图,View类内部变量包含了一个标志位DRAWN,当该视图需要重绘时,就会为该View添加该标志位。

  • View 的关键生命周期

View 的关键生命周期为 [改变可见性] –> 构造View –> onFinishInflate –> onAttachedToWindow –> onMeasure –> onSizeChanged –> onLayout –> onDraw –> onDetackedFromWindow

  • Android中图片占用内存的计算

ARGB_4444 每个像素2字节
RGB_565 每个像素2字节
ARGB_8888 每个像素4字节。

那么一张720p的图片,就要占用72012804 大概3.5兆的大小,所以图片处理很重要,不然分分钟OOM

  • ART和Dalvik区别

Art上应用启动快,运行快,但是耗费更多存储空间,安装时间长,总的来说ART的功效就是”空间换时间”。

ART: Ahead of Time Dalvik: Just in Time

什么是Dalvik:Dalvik是Google公司自己设计用于Android平台的Java虚拟机。Dalvik虚拟机是Google等厂商合作开发的Android移动设备平台的核心组成部分之一,它可以支持已转换为.dex(即Dalvik Executable)格式的Java应用程序的运行,.dex格式是专为Dalvik应用设计的一种压缩格式,适合内存和处理器速度有限的系统。Dalvik经过优化,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik应用作为独立的Linux进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。

什么是ART:Android操作系统已经成熟,Google的Android团队开始将注意力转向一些底层组件,其中之一是负责应用程序运行的Dalvik运行时。Google开发者已经花了两年时间开发更快执行效率更高更省电的替代ART运行时。ART代表Android Runtime,其处理应用程序执行的方式完全不同于Dalvik,Dalvik是依靠一个Just-In-Time(JIT)编译器去解释字节码。开发者编译后的应用代码需要通过一个解释器在用户的设备上运行,这一机制并不高效,但让应用能更容易在不同硬件和架构上运行。ART则完全改变了这套做法,在应用安装的时候就预编译字节码到机器语言,这一机制叫Ahead-Of-Time(AOT)编译。在移除解释代码这一过程后,应用程序执行将更有效率,启动更快。

ART优点:

  1. 系统性能的显著提升
  2. 应用启动更快、运行更快、体验更流畅、触感反馈更及时
  3. 更长的电池续航能力
  4. 支持更低的硬件

ART缺点:

  1. 更大的存储空间占用,可能会增加10%-20%
  2. 更长的应用安装时间

    • 关于include

如果我们要在标签中覆写layout属性,必须要将layout_width和layout_height这两个属性也进行覆写,否则覆写xiaoguo将不会生效。

  • Android几种进程

  1. 前台进程:即与用户正在交互的Activity或者Activity用到的Service等,如果系统内存不足时前台进程是最后被杀死的
  2. 可见进程:可以是处于暂停状态(onPause)的Activity或者绑定在其上的Service,即被用户可见,但由于失去了焦点而不能与用户交互
  3. 服务进程:其中运行着使用startService方法启动的Service,虽然不被用户可见,但是却是用户关心的,例如用户正在非音乐界面听的音乐或者正在非下载页面自己下载的文件等;当系统要空间运行前两者进程时才会被终止
  4. 后台进程:其中运行着执行onStop方法而停止的程序,但是却不是用户当前关心的,例如后台挂着的QQ,这样的进程系统一旦没了有内存就首先被杀死
  5. 空进程:不包含任何应用程序的程序组件的进程,这样的进程系统是一般不会让他存在的

如何避免后台进程被杀死:

  1. 调用startForegound,让你的Service所在的线程成为前台进程
  2. Service的onStartCommond返回START_STICKY或START_REDELIVER_INTENT
  3. Service的onDestroy里面重新启动自己

    • 65K问题

对Android方法数不能超过65K的限制应该有所耳闻,随着应用程序功能不断的丰富,总有一天你会遇到一个异常:

Conversion to Dalvik format failed:Unable toexecute dex: method ID not in [0, 0xffff]: 65536

Android系统中,一个Dex文件中存储方法id用的是short类型数据,所以导致你的dex中方法不能超过65k

解决方法是dex分包

dex.force.jumbo=true
是的,加入了这句话,确实可以让你的应用通过编译,但是在一些2.3系统的机器上很容易出现
INSTALL_FAILED_DEXOPT异常

详细方法见:彻底解决Android 应用方法数不能超过65K的问题

  • Android使用static静态代码块最多的地方

ContentProvider中,用来初始化UriMatcher

1
2
3
4
5
6
7
8
9
private static final UriMatcher
sURLMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURLMatcher.addURI("mms", null, MMS_ALL);
sURLMatcher.addURI("mms", "#", MMS_ALL_ID);
}
private SQLiteOpenHelper mOpenHelper;
  • SurfaceTexture 的好处

可以在不使用SurfaceView的情况下,获取到摄像头的数据,并且自己做相应处理.

  • 摄像头数据那点事

    摄像头数据在

    public void onPreviewFrame(byte[] data, Camera camera)

回调中拿到手,到手的为YUV420SP数据,需要转成bitmap处理,最好是Bitmap.Config.RGB_565.

  • 查看每个应用程序最高可用内存:

1
2
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
Log.d("TAG", "Max memory is " + maxMemory + "KB");
  • java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v7

原因是:

1
2
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.0.1'

问题是v7和design版本不一致 改成一样的搞版本就好

  • Format格式化

    使用Resources#getString(int id, Object… formatArgs)格式化字符串

千万别用“+”这种操作符,因为在不同语言单词排列顺序可能是不一样的

res/values/strings.xml

java code

正确的方式是使用 Resources#getString(int id, Object… formatArgs)

res/values/strings.xml

res/values-UA/strings.xml

java code

正确的方式是使用 Resources#getString(int id, Object… formatArgs)

  • 字符高亮

    使用html文本高亮静态字符

如果你想改变TextView字符串的颜色-ForegroundColorSpan 并不是一个任何时候都好用的一个选择,因为高亮是通过下标index来实现的,在多语言app里面并不安全(译者:你要手动计算不同语言同一个单词的index,容易数组下标越界)。更好的做法是使用strings.xml里面的html font颜色标签。

假设你有一个文本“Discover and play games.” 然后你想高亮“Discover”单词和“play”单词成蓝色。

java code

  • Intent Filter

  android的3个核心组件——Activity、services、广播接收器——是通过intent传递消息的。intent消息用于在运行时绑定不同的组件。
  在 Android 的 AndroidManifest.xml 配置文件中可以通过 intent-filter 节点为一个 Activity 指定其 Intent Filter,以便告诉系统该 Activity 可以响应什么类型的 Intent。

intent-filter 的三大属性

  1. Action

  一个 Intent Filter 可以包含多个 Action,Action 列表用于标示 Activity 所能接受的“动作”,它是一个用户自定义的字符串。

  

1
2
3
4
5
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<action android:name="com.scu.amazing7Action" />
……
</intent-filter>

在代码中使用以下语句便可以启动该Intent 对象:

1
2
Intent i=new Intent();
i.setAction("com.scu.amazing7Action");

Action 列表中包含了“com.scu.amazing7Action”的 Activity 都将会匹配成功

  1. URL

  在 intent-filter 节点中,通过 data节点匹配外部数据,也就是通过 URI 携带外部数据给目标组件。

1
2
3
4
5
<data android:mimeType="mimeType"
android:scheme="scheme"
android:host="host"
android:port="port"
android:path="path"/>

注意:只有data的所有的属性都匹配成功时 URI 数据匹配才会成功

  1. Category

  为组件定义一个 类别列表,当 Intent 中包含这个类别列表的所有项目时才会匹配成功。

1
2
3
4
<intent-filter . . . >
<action android:name="code android.intent.action.MAIN" />
<category android:name="code android.intent.category.LAUNCHER" />
</intent-filter>
  • Activity 中 Intent Filter 的匹配过程

  ①加载所有的Intent Filter列表

  ②去掉action匹配失败的Intent Filter

  ③去掉url匹配失败的Intent Filter

  ④去掉Category匹配失败的Intent Filter

  ⑤判断剩下的Intent Filter数目是否为0。如果为0查找失败返回异常;如果大于0,就按优先级排序,返回最高优先级的Intent Filter

  • 开发中Activity的一些问题

    一般设置Activity为非公开的  

1
2
3
<activity
......
android:exported="false" />

注意:非公开的Activity不能设置intent-filter,以免被其他activity唤醒(如果拥有相同的intent-filter)。

  • 不要指定activity的taskAffinity属性

  • 不要设置activity的LaunchMode(保持默认)

  注意Activity的intent最好也不要设定为FLAG_ACTIVITY_NEW_TASK

  • 在匿名内部类中使用this时加上activity类名(类名.this,不一定是当前activity)

  • 设置activity全屏

      在其 onCreate()方法中加入:

1
2
3
4
// 设置全屏模式
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 去除标题栏
requestWindowFeature(Window.FEATURE_NO_TITLE);
  • Android去除系统自带动画的两种方法

方法一:

在startActivity()或者finish()后紧跟调用:

1
((Activity) mContext).overridePendingTransition(0, 0);

方法二:
在一些特殊情况下方法一是不能实现的.
比如给Intent设置了属性:

intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

此时可以这么做:
1.在styles.xml下添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<style name="Theme" parent="android:Theme">
<item name="android:windowAnimationStyle">@style/noAnimation</item>
<item name="android:windowNoTitle">true</item>
</style>
<style name="noAnimation">
<item name="android:activityOpenEnterAnimation">@null</item>
<item name="android:activityOpenExitAnimation">@null</item>
<item name="android:activityCloseEnterAnimation">@null</item>
<item name="android:activityCloseExitAnimation">@null</item>
<item name="android:taskOpenEnterAnimation">@null</item>
<item name="android:taskOpenExitAnimation">@null</item>
<item name="android:taskCloseEnterAnimation">@null</item>
<item name="android:taskCloseExitAnimation">@null</item>
<item name="android:taskToFrontEnterAnimation">@null</item>
<item name="android:taskToFrontExitAnimation">@null</item>
<item name="android:taskToBackEnterAnimation">@null</item>
<item name="android:taskToBackExitAnimation">@null</item>
</style>

2.在AndroidManifest.xml中为跳出和跳入的Activity设置:

android:theme=”@style/Theme”

  • ###

    说说AsyncTask的源码设计

    当我们调用execute的时候,其实是去调executeOnExecutor,传入我们的默认执行器的.从代码中,我们能看到,默认的执行器是一个串行的执行器.当然,这个串行执行器会再将runnable给一个ThreadPoolExecutor来执行, 这个ThreadPoolExecutor 默认大小是处理器的核心数的2倍+1, 比如我们是双核,也就是默认大小为5个线程.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
  • 子线程更新UI那点事情

在onCreate或者onResume中, 直接开一个线程更新UI是可以的, 在Activity刚刚起来的时候, ViewRootImpl不会走checkTHread 方法, 因为mParent为空.

但是当Activity存活了一会儿,比如我们设置个button点击事件, 然后点击触发使用线程修改UI, 便会报错

  • ###
  • ###
  • ###
  • ###

###谢谢大家阅读,如有帮助,来个喜欢或者关注吧!


本文作者:Anderson/Jerey_Jobs

简书地址:Anderson大码渣

github地址:Jerey_Jobs